package com.bestcem.xm.ticket.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.lang.Validator;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ValidationErrorCodeEnum;
import com.bestcem.xm.ticket.constant.Constants;
import com.bestcem.xm.ticket.controller.param.FollowTicketParam;
import com.bestcem.xm.ticket.controller.param.ReopenTicketParam;
import com.bestcem.xm.ticket.controller.param.ticket.InsertTicketParam;
import com.bestcem.xm.ticket.controller.param.ticket.TransferTicketParam;
import com.bestcem.xm.ticket.controller.param.ticket.config.NotifyConfigParam;
import com.bestcem.xm.ticket.controller.vo.SimpleIdVO;
import com.bestcem.xm.ticket.dao.*;
import com.bestcem.xm.ticket.dao.dto.TicketInfo;
import com.bestcem.xm.ticket.entity.mongo.*;
import com.bestcem.xm.ticket.enums.*;
import com.bestcem.xm.ticket.grpc.client.TicketBaseUserGrpcService;
import com.bestcem.xm.ticket.grpc.client.TicketUserGrpcService;
import com.bestcem.xm.ticket.grpc.client.dto.user.GroupDTO;
import com.bestcem.xm.ticket.grpc.client.dto.user.GroupLevelDTO;
import com.bestcem.xm.ticket.grpc.client.dto.user.RoleDTO;
import com.bestcem.xm.ticket.grpc.client.dto.user.UserDTO;
import com.bestcem.xm.ticket.service.TicketOperateService;
import com.bestcem.xm.ticket.service.TicketService;
import com.bestcem.xm.ticket.service.convert.TicketInfoConvert;
import com.bestcem.xm.ticket.service.convert.TicketRecordConvert;
import com.bestcem.xm.ticket.service.dto.ticket.CloseTicketDTO;
import com.bestcem.xm.ticket.service.dto.ticket.CreateTicketDTO;
import com.bestcem.xm.ticket.service.manager.fsm.TicketFsmManager;
import com.bestcem.xm.ticket.service.manager.record.param.TransferParam;
import com.bestcem.xm.ticket.service.manager.record.param.TransferTicketRecordParam;
import com.bestcem.xm.ticket.util.CommonUtils;
import com.bestcem.xm.ticket.util.TicketUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.bestcem.xm.ticket.service.manager.role.TicketFollower.SUBMIT_SUPER_ADMIN;

/**
 * 工单的各类操作
 * 手动创建/转派/关闭/重新打开/跟进
 *
 * @author XiaoYunSong <ys.xiao@idiaoyan.com>
 * @version dingtalk
 * @date 2021/12/7 14:43
 */
@Slf4j
@Service
public class TicketOperateServiceImpl implements TicketOperateService {

    @Resource
    private TicketService ticketService;

    @Resource
    private TicketUserGrpcService ticketUserGrpcService;
    @Resource
    private TicketBaseUserGrpcService ticketBaseUserGrpcService;


    @Resource
    private TicketDao ticketDao;
    @Resource
    private TemplateDao templateDao;
    @Resource
    private TicketFlowDao ticketFlowDao;
    @Resource
    private TicketRecordDao ticketRecordDao;
    @Resource
    private TicketConfigDao ticketConfigDao;
    @Resource
    private TicketNotifyConfigDao ticketNotifyConfigDao;

    @Resource
    private TicketUtil ticketUtil;
    @Resource
    private TicketFsmManager ticketFsmManager;
    @Resource
    private CommonUtils commonUtils;


    /**
     * 手动创建工单
     *
     * @return ticket_record的id
     * @author zq.ding <zq.ding@idiaoyan.com>
     * @date 2021/8/19 19:44
     * @date 2022/2/24 18:03 XiaoYunSong 消息库2.0 手动创建工单对接消息库
     */
    @Override
    public ServiceResult<SimpleIdVO> createTicket(InsertTicketParam ticketParam) {
        if (log.isInfoEnabled()) {
            log.info("[ticket] 手动创建工单请求：param={}", ticketParam);
        }
        String errorMsg = validCreateTicketParam(ticketParam);
        if (Validator.isNotNull(errorMsg)) {
            return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_FORMAT, errorMsg);
        }
        UserDTO userDTO = ticketBaseUserGrpcService.getUser(ticketParam.getUserId());
        if (Objects.isNull(userDTO)) {
            return ServiceResult.failWithCode(ResourceErrorCodeEnum.NOT_FOUND, "登录用户不存在");
        }
        // 1. 获取regionName
//        Map<String, String> groupIdName = getGroupIdName(ticketParam);
        // 2. 创建工单Dto
        CreateTicketDTO createTicketDTO = new CreateTicketDTO();
        createTicketDTO.setOrgId(ticketParam.getOrgId());
        // 手动创建工单不设置工单层级
//        createTicketDTO.setRegionName(groupIdName.getOrDefault("groupName", "全国"));
//        createTicketDTO.setRegionId(groupIdName.get("groupId"));
        createTicketDTO.setTicketName(ticketParam.getName());
        createTicketDTO.setNeedDeal(true);
        // 设置用户姓名
        createTicketDTO.setCreatedName(userDTO.getName());
        createTicketDTO.setCreatedId(ticketParam.getUserId());
        // 手动创建
        createTicketDTO.setOperationType(2);
        createTicketDTO.setDetailTemplateId(ticketParam.getDetailTemplateId());
        createTicketDTO.setHandleTemplateId(ticketParam.getHandleTemplateId());

        if (log.isInfoEnabled()) {
            log.info("[ticket] 创建工单。获取模板");
        }
        // 3. 根据处理id查询处理模板
        TicketTemplateV2 handleTemplate = templateDao.getTemplateById(ticketParam.getHandleTemplateId());
        if (Validator.isNull(handleTemplate)) {
            return ServiceResult.fail("处理模板id没有对应的处理模板");
        }
        if (log.isInfoEnabled()) {
            log.info("[ticket] 创建工单。工单配置保存");
        }
        // 4. 根据参数保存工单配置
        TicketConfig ticketConfig = saveTicketConfig(ticketParam);
        if (log.isInfoEnabled()) {
            log.info("[ticket] 创建工单。工单配置={}保存成功", ticketConfig);
        }
        // 工单中添加联系人id
        createTicketDTO.setMemberId(CollUtil.isNotEmpty(ticketConfig.getMemberIds()) ? String.join(",", ticketConfig.getMemberIds()) : "");

        ticketParam.setTicketConfigId(ticketConfig.getId());
        // 5. 保存工单通知配置信息
        List<String> ticketNotifyConfigIds = saveTicketNotifyConfig(ticketParam);
        if (log.isInfoEnabled()) {
            log.info("[ticket] 创建工单。工单通知配置信息={}保存成功", ticketNotifyConfigIds);
        }
        ticketParam.setTicketNotifyConfigIds(ticketNotifyConfigIds);
        // 6. 更新工单配置表中的TICKET_NOTIFY_CONFIG_IDS
        ticketConfigDao.updateTicketNotifyConfigIds(ticketConfig.getId(), ticketNotifyConfigIds);
        // 7. 获取工单跟进人信息
        TicketFlow ticketFlow = saveTicketFlow(ticketParam);
        if (log.isInfoEnabled()) {
            log.info("[ticket] 开始创建工单，创建参数param={}", createTicketDTO);
        }
        // 8 创建工单
        Ticket ticket = ticketUtil.generateTicket(ticketConfig, ticketFlow, handleTemplate, createTicketDTO);
        // 暂定手动创建工单不发送mq
        // 9. 工单状态流转
        try {
            TransferParam transferParam = new TransferParam();
            transferParam.setUserName(userDTO.getName());
            transferParam.setUserId(ticketParam.getUserId());
            transferParam.setOrgId(ticketParam.getOrgId());
            ticketFsmManager.transfer(ticket, TicketEventEnum.USER_CREATED, transferParam);
        } catch (Exception e) {
            log.error("[ticket] 工单创建，工单状态流转失败", e);
            return ServiceResult.fail("工单创建，工单状态流转失败");
        }
        return ServiceResult.success(new SimpleIdVO(ticket.getId()));
    }


    /**
     * 跟进工单
     *
     * @return 工单id
     * @author liheng
     * @date 2021/8/26 16:57
     */
    @Override
    public ServiceResult<String> followTicket(FollowTicketParam param) {
        if (this.validateFields(param)) {
            List<String> ancestorIds = ticketUserGrpcService.listAncestorIdsByUserId(param.getUserId());
            // 获取组织id
            String gid = "";
            if (!CollectionUtils.isEmpty(ancestorIds)) {
                gid = ancestorIds.get(0);
            }
            // 获取组织名
            if (Objects.nonNull(gid) && ObjectId.isValid(gid)) {
                GroupDTO group = ticketBaseUserGrpcService.getGroup(gid);
                if (Objects.nonNull(group)) {
                    param.setRegionName(group.getTitle());
                } else {
                    param.setRegionName("全国");
                }
            }

            Ticket ticket = ticketDao.findById(param.getTicketId());
            if (!TicketStatusEnum.FOLLOWING.getIndex().equals(ticket.getStatus())) {
                return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_FORMAT, "当前状态不可跟进");
            }
            TransferParam transferParam;

            transferParam = new TransferParam();
            // 旧数据字段，2.3版本已去除审核
            if (Integer.valueOf(0).equals(param.getIsCompleted())) {
                transferParam.setIsCompleted(false);
            } else {
                transferParam.setIsCompleted(false);
            }
            transferParam.setOrgId(param.getOrgId());
            transferParam.setUserId(param.getUserId());
            transferParam.setUserName(param.getUserName());
            transferParam.setRegionName(param.getRegionName());
            transferParam.setTicketId(param.getTicketId());
            transferParam.setContent(param.getContent());
            transferParam.setTemplateId(param.getTemplateId());
            transferParam.setTemplateFields(param.getTemplateFields());
            return ticketFsmManager.transfer(ticket, TicketEventEnum.COMMIT_FOLLOWED, transferParam);

        } else {
            return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_LOST, "缺少必填项");
        }
    }


    /**
     * 转派工单
     *
     * @author liheng
     * @author 2021/12/7 15:03 XiaoYunSong <ys.xiao@idiaoyan.com> 工单对接钉钉需求, 新增组织转派, 同时转派时重新分配工单组织
     * @date 2021/9/8 18:07
     */
    @Override
    public ServiceResult<SimpleIdVO> transferTicket(TransferTicketParam param) {
        String ticketId = param.getTicketId();
        Ticket ticket = ticketDao.findById(ticketId);
        if (Objects.isNull(ticket)) {
            return ServiceResult.failWithCode(ResourceErrorCodeEnum.NOT_FOUND, "工单/预警不存在");
        }
        if (!CollectionUtils.isEmpty(ticket.getCurFollowUserId()) && ticket.getCurFollowUserId().contains(param.getUserId())) {
            return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_LOST, "工单不可以转派给当前处理人");
        }

        TicketStatusEnum status = TicketStatusEnum.getByIndex(ticket.getStatus());
        if (TicketStatusEnum.CLOSED.equals(status)) {
            return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_LOST, "当前状态不可转派");
        }

        // 内部水平权限校验
        boolean hasPermission = false;
        if (TicketOperationTypeEnum.MANUAL.getIndex().equals(ticket.getOperationType())) {
            if (param.getDispatcherId().equals(ticket.getCreatedId())) {
                hasPermission = true;
            }
        }
        TicketInfo ticketInfo = TicketInfoConvert.entityToInfo(ticket);
        List<UserDTO> currentTicketUsers = ticketService.getCurrentTicketUsers(ticketInfo);
        if (!CollectionUtils.isEmpty(currentTicketUsers)) {
            Set<String> currentTicketUserIds = currentTicketUsers.stream().map(UserDTO::getId).collect(Collectors.toSet());
            if (currentTicketUserIds.contains(param.getDispatcherId())) {
                hasPermission = true;
            }
        }
        if (!hasPermission) {
            return ServiceResult.failWithCode(ResourceErrorCodeEnum.PERMISSION_DENY, "当前用户无权限转派");
        }

        // 按用户转派
        if (FollowerFilterEnum.USER.getIndex().equals(param.getUserFilter())) {
            param.setGroupId(Constants.BLANK);
            param.setGroupName(Constants.BLANK);

            UserDTO user = ticketBaseUserGrpcService.getUser(param.getUserId());
            if (Objects.isNull(user)) {
                return ServiceResult.failWithCode(ResourceErrorCodeEnum.NOT_FOUND, "用户不存在");
            }
            // 获取用户的组织信息
            List<String> ancestorIds = ticketUserGrpcService.listAncestorIdsByUserId(param.getUserId());
            // 普通用户无组织不允许转派
            if (CollectionUtils.isEmpty(ancestorIds)) {
                Set<String> orgAllAdminId = commonUtils.getOrgAllAdminId(param.getOrgId());
                if (!orgAllAdminId.contains(param.getUserId())) {
                    return ServiceResult.failWithCode(ResourceErrorCodeEnum.NOT_FOUND, "用户无所属组织");
                }
            } else {
                GroupDTO group = ticketBaseUserGrpcService.getGroup(ancestorIds.get(0));
                if (Objects.isNull(group) || !ObjectId.isValid(group.getId())) {
                    return ServiceResult.failWithCode(ResourceErrorCodeEnum.NOT_FOUND, "用户组织信息错误");
                }
                param.setGroupId(group.getId());
                param.setGroupName(group.getTitle());
            }
        }
        // 按组织转派
        if (FollowerFilterEnum.REGION.getIndex().equals(param.getUserFilter())) {
            RoleDTO role = ticketBaseUserGrpcService.getRole(param.getRoleId());
            if (Objects.isNull(role)) {
                return ServiceResult.failWithCode(ResourceErrorCodeEnum.NOT_FOUND, "角色不存在");
            }
            param.setRoleName(role.getTitle());
            GroupDTO group = ticketBaseUserGrpcService.getGroup(param.getGroupId());
            if (Objects.isNull(group)) {
                return ServiceResult.failWithCode(ResourceErrorCodeEnum.NOT_FOUND, "组织不存在");
            }
            param.setGroupName(group.getTitle());
            if (!ObjectId.isValid(group.getGroupLevelId())) {
                return ServiceResult.failWithCode(ValidationErrorCodeEnum.OID_ERROR, "组织层级id错误");
            }
            GroupLevelDTO groupLevel = ticketBaseUserGrpcService.getGroupLevel(group.getGroupLevelId());
            if (Objects.isNull(groupLevel)) {
                return ServiceResult.failWithCode(ResourceErrorCodeEnum.NOT_FOUND, "组织层级不存在");
            }
            param.setGroupLevelId(groupLevel.getId());
            param.setGroupLevelName(groupLevel.getTitle());
        }

        TransferTicketRecordParam recordParam = TicketRecordConvert.paramToRecordParam(param);

        // 获取操作人的组织信息, 这里的dispatcherId就是操作人的id
        List<String> ancestorIds = ticketUserGrpcService.listAncestorIdsByUserId(param.getDispatcherId());
        if (CollectionUtils.isEmpty(ancestorIds)) {
            recordParam.setRegionName("全国");
        } else {
            GroupDTO group = ticketBaseUserGrpcService.getGroup(ancestorIds.get(0));
            recordParam.setRegionId(Optional.ofNullable(group).orElse(new GroupDTO()).getId());
            recordParam.setRegionName(Optional.ofNullable(group).orElse(new GroupDTO()).getTitle());
        }

        // 工单转派
        ServiceResult<String> result = ticketFsmManager.transferTicket(ticket, recordParam);
        if (!result.isSuccess()) {
            return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_FORMAT, result.getMsg());
        }
        return ServiceResult.success(new SimpleIdVO(result.getData()));
    }


    /**
     * 关闭工单
     *
     * @return ticket_record的id
     * @author zq.ding <zq.ding@idiaoyan.com>
     * @date 2021/8/19 19:44
     */
    @Override
    public ServiceResult<SimpleIdVO> closeTicket(CloseTicketDTO param) {
        String ticketId = param.getTicketId();
        Ticket ticket = ticketDao.findById(ticketId);
        if (Objects.isNull(ticket)) {
            return ServiceResult.failWithCode(
                    ResourceErrorCodeEnum.NOT_FOUND, "ticket_id: " + ticketId + " status is following not found");
        }
        TicketStatusEnum status = TicketStatusEnum.getByIndex(ticket.getStatus());
        if (!TicketStatusEnum.FOLLOWING.equals(status)) {
            return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_LOST, "当前状态不可关闭");
        }
        if (Objects.nonNull(ticket.getNeedRecord()) && ticket.getNeedRecord()) {
            TicketRecord ticketRecord = ticketRecordDao.findFollowByTicketId(ticketId);
            if (Objects.isNull(ticketRecord)) {
                return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_LOST, "请提交跟进记录");
            }
        }
        TransferParam transferParam = CloseTicketDTO.toTransferParam(param);
        if (Objects.isNull(transferParam)) {
            log.error("[Ticket] 关闭工单初始化流转参数失败; Param: {}", param);
            return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_FORMAT, "未知错误");
        }
        ServiceResult<String> transferResult = ticketFsmManager.transfer(ticket, TicketEventEnum.MANUAL_CLOSED, transferParam);
        if (!transferResult.isSuccess()) {
            return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_FORMAT, transferResult.getMsg());
        }
        return ServiceResult.success(new SimpleIdVO(transferResult.getData()));
    }


    /**
     * 重新打开工单
     *
     * @return ticket_record的id
     * @author zq.ding <zq.ding@idiaoyan.com>
     * @date 2021/8/19 19:44
     */
    @Override
    public ServiceResult<SimpleIdVO> reopenTicket(ReopenTicketParam param) {
        if (Objects.isNull(param)) {
            log.error("[Ticket] 重新打开工单初始化流转参数失败; Param: {}", param);
            return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_FORMAT, "未知错误");
        }

        String ticketId = param.getTicketId();
        Ticket ticket = ticketDao.findById(ticketId);
        if (Objects.isNull(ticket)) {
            return ServiceResult.failWithCode(ResourceErrorCodeEnum.NOT_FOUND, "ticket_id: " + ticketId + " status not found");
        }
        TicketStatusEnum status = TicketStatusEnum.getByIndex(ticket.getStatus());
        if (!(TicketStatusEnum.CLOSED.equals(status) || TicketStatusEnum.MANUAL_CLOSED.getIndex().equals(ticket.getStatus())
                || TicketStatusEnum.SYSTEM_CLOSED.equals(status))) {
            return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_LOST, "当前状态不可重新打开");
        }

        ServiceResult<String> transferResult = ticketFsmManager.reopenTicket(ticket, TicketEventEnum.REOPEN, param);
        if (!transferResult.isSuccess()) {
            return ServiceResult.failWithCode(ReqErrorCodeEnum.PARAM_FORMAT, transferResult.getMsg());
        }
        return ServiceResult.success(new SimpleIdVO(transferResult.getData()));
    }


    // ================================ private method ================================


    /**
     * 判断工单跟进模板字段必填项
     *
     * @author liheng
     * @date 2021/8/26 16:32
     */
    private boolean validateFields(FollowTicketParam param) {
        // 原python代码中未校验content，
//        if (Objects.isNull(param.getContent())){
//            return false;
//        }
        // 工单2.2P2 改版 删除了defaultFields 字段，只需校验 custom_fields
        // 2.3版本去除该字段
//        List<FollowTicketParam.CustomFieldParam> customFields = param.getCustomFields();
//        for (FollowTicketParam.CustomFieldParam customField : customFields) {
//            if (Objects.nonNull(customField.getRequired())) {
//                String field = customField.getField();
//                String fieldNumber = field.substring(field.length() - 1);
//                boolean field1Required = "1".equals(fieldNumber) && Objects.isNull(param.getField1());
//                boolean field2Required = "2".equals(fieldNumber) && Objects.isNull(param.getField2());
//                boolean field3Required = "3".equals(fieldNumber) && Objects.isNull(param.getField3());
//                if (field1Required || field2Required || field3Required) {
//                    if (log.isInfoEnabled()) {
//                        log.info("[ticket]:{}字段为必填项", customField.getText());
//                    }
//                    return false;
//                }
//            }
//        }
        if (CollUtil.isEmpty(param.getTemplateFields())) {
            if (log.isInfoEnabled()) {
                log.info("[tikcet]: 跟进工单-工单中处理模板字段为空，TemplateFields:{}", param.getTemplateFields());
            }
            return false;
        }
        for (InsertTicketParam.TemplateField templateField : param.getTemplateFields()) {
            if (Objects.nonNull(templateField.getRequired())) {
                if (templateField.getRequired() && StringUtils.isBlank(templateField.getAnswer())) {
                    if (log.isInfoEnabled()) {
                        log.info("[ticket]:{}字段为必填项,字段信息：{}", templateField.getName(), templateField);
                        return false;
                    }
                }
            } else {
                if (log.isInfoEnabled()) {
                    // todo： 必填字段required缺失
                }
            }
        }
        return true;
    }


    /**
     * 手动创建工单 - 校验创建工单参数
     *
     * @param ticketParam 工单参数
     * @return String 错误信息
     * @author jy.zhao
     * @date 2021/9/8 22:05
     **/
    private String validCreateTicketParam(InsertTicketParam ticketParam) {
        if (Validator.isEmpty(ticketParam.getName())) {
            return "工单名称不能为空";
        }
        if (Validator.isEmpty(ticketParam.getDetailTemplateId())) {
            return "详情模板id不能为空";
        }
        if (Validator.isEmpty(ticketParam.getHandleTemplateId())) {
            return "处理模板id不能为空";
        }
        // 校验详情模板字段
        List<InsertTicketParam.TemplateField> templateDetailFields = ticketParam.getTemplateDetailFields();
        if (Validator.isNotNull(templateDetailFields)) {
            for (InsertTicketParam.TemplateField templateField : templateDetailFields) {
                if (templateField.getRequired() && Validator.isEmpty(templateField.getAnswer())) {
                    return "详情模板" + templateField.getName() + "答案不能为空";
                }
            }
        }
        // 校验跟进人信息
        InsertTicketParam.FollowConfig followConfig = ticketParam.getFollowConfig();
        if (Validator.isNull(followConfig)) {
            return "跟进人信息不能为空";
        }
        if (Validator.isNull(followConfig.getUserFilter())) {
            return "用户过滤条件不能为空";
        }
        if (followConfig.getUserFilter() == 0 && Validator.isEmpty(followConfig.getRegionId())) {
            return "用户区域id不能为空";
        }
        if (followConfig.getUserFilter() == 0 && Validator.isEmpty(followConfig.getRoleId())) {
            return "用户角色id不能为空";
        }
        if (followConfig.getUserFilter() == 1 && Validator.isEmpty(followConfig.getUserId())) {
            return "用户id不能为空";
        }
        return null;
    }


    /**
     * 手动创建工单 - 保存工单配置
     *
     * @param ticketParam 工单参数
     * @return TicketConfig 工单配置
     * @author jy.zhao
     * @date 2021/9/8 19:29
     **/
    private TicketConfig saveTicketConfig(InsertTicketParam ticketParam) {
        TicketConfig ticketConfig = new TicketConfig();
        ticketConfig.setSysId("ticket");
        ticketConfig.setOrgId(ticketParam.getOrgId());
        ticketConfig.setUserId(ticketParam.getUserId());
        ticketConfig.setCreateTrigger(TicketConfigCreateTriggerEnum.ENABLE.getIndex());
        // 设置处理模板的id
        ticketConfig.setTicketTemplateId(ticketParam.getHandleTemplateId());
        // 设置详情模板的id
        ticketConfig.setDetailTemplateId(ticketParam.getDetailTemplateId());
        // 通知处理人
        ticketConfig.setNotifyHandler(ticketParam.getNotifyHandler());
        List<Ticket.TemplateDetailField> templateDetailFields = new ArrayList<>();
        // 设置模板详情内容
        if (Validator.isNotNull(ticketParam.getTemplateDetailFields())) {
            HashSet<String> memberIds = new HashSet<>(16);
            for (InsertTicketParam.TemplateField templateFieldParam : ticketParam.getTemplateDetailFields()) {
                Ticket.TemplateDetailField templateDetailField = new Ticket.TemplateDetailField();
                templateDetailField.setContent(templateFieldParam.getName());
                // 设置答案
                Ticket.TemplateDetailField.SurveyAnswer surveyAnswer = new Ticket.TemplateDetailField.SurveyAnswer();
                surveyAnswer.setAnswer(templateFieldParam.getAnswer());
                templateDetailField.setValue(surveyAnswer);
                // 设置题型
                templateDetailField.setType(templateFieldParam.getType());
                // 答案是否必填
                templateDetailField.setRequired(templateFieldParam.getRequired());
                templateDetailFields.add(templateDetailField);
                // 联系人id处理，用作生成足迹点
                if (ObjectId.isValid(templateFieldParam.getMemberId())) {
                    memberIds.add(templateFieldParam.getMemberId());
                }
            }
            ticketConfig.setMemberIds(memberIds);
        }
        ticketConfig.setTemplateDetailFields(templateDetailFields);
        if (log.isInfoEnabled()) {
            log.info("[ticket] 创建工单配置，创建参数param={}", ticketConfig);
        }
        return ticketConfigDao.saveTicketConfig(ticketConfig);
    }


    /**
     * 手动创建工单 - 保存工单通知配置
     *
     * @param ticketParam 工单参数
     * @return TicketFlow 工单流转
     * @author jy.zhao
     * @date 2021/9/8 19:06
     * @date 2022/2/24 18:03 XiaoYunSong 消息库2.0 手动创建工单对接消息库
     **/
    private List<String> saveTicketNotifyConfig(InsertTicketParam ticketParam) {
        List<String> result = new ArrayList<>();
        List<NotifyConfigParam> ticketNotifyConfigList = ticketParam.getTicketNotifyConfigList();
        if (CollectionUtils.isEmpty(ticketNotifyConfigList)) {
            ticketNotifyConfigList = new ArrayList<>();
            // 生成工单/跟进通知/跟进逾期
            for (int i = 0; i <= 2; i++) {
                NotifyConfigParam temp = new NotifyConfigParam();
                temp.setEvent(i);
                ticketNotifyConfigList.add(temp);
            }
        }
        // 租户 Id
        String orgId = ticketParam.getOrgId();
        // TicketConfigId
        String ticketConfigId = ticketParam.getTicketConfigId();
        // 邮箱SMTP Id
        String smtpId = ticketParam.getSmtpId();
        // 通知方式
        NotifySetting.Way way = new NotifySetting.Way();
        if (Validator.isNotNull(ticketParam.getNotifyWays())) {
            way.setEmail(ticketParam.getNotifyWays().getEmail());
            way.setSms(ticketParam.getNotifyWays().getSms());
            way.setFeiShu(ticketParam.getNotifyWays().getFeiShu());
            way.setWeChatWork(ticketParam.getNotifyWays().getWeChatWork());
            way.setDingtalk(ticketParam.getNotifyWays().getDingtalk());
        }
        // 是否启用
        int status = Boolean.TRUE.equals(ticketParam.getNotifyHandler()) ? 1 : 0;
        // 收件人
        TicketNotifyConfig.ReceiveUser receiveUser = new TicketNotifyConfig.ReceiveUser();
        InsertTicketParam.FollowConfig followConfig = ticketParam.getFollowConfig();
        receiveUser.setId(followConfig.getUserId());
        receiveUser.setUserName(followConfig.getName());
        receiveUser.setEmail(followConfig.getEmail());
        receiveUser.setFollowerFilter(followConfig.getUserFilter());
        receiveUser.setRegion(followConfig.getRegionId());
        receiveUser.setRoleId(followConfig.getRoleId());
        // 抄送人
        List<TicketNotifyConfig.RoleRegion> ccList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(ticketParam.getCcList())) {
            for (InsertTicketParam.UserInfo userInfo : ticketParam.getCcList()) {
                TicketNotifyConfig.RoleRegion roleRegion = new TicketNotifyConfig.RoleRegion();
                roleRegion.setCcId(userInfo.getUserId());
                roleRegion.setCcFilter(userInfo.getUserFilter());
                roleRegion.setRegion(StringUtils.isBlank(userInfo.getRegionId()) ? null : userInfo.getRegionId());
                roleRegion.setRoleId(StringUtils.isBlank(userInfo.getRoleId()) ? null : userInfo.getRoleId());
                ccList.add(roleRegion);
            }
        }

        // 保存工单通知配置
        for (NotifyConfigParam param : ticketNotifyConfigList) {
            TicketNotifyConfig notifyConfig = new TicketNotifyConfig();
            notifyConfig.setOrgId(orgId);
            notifyConfig.setTicketConfigId(ticketConfigId);
            notifyConfig.setSmtpId(smtpId);
            notifyConfig.setStatus(status);
            notifyConfig.setWays(way);
            // 设置处理人. 手动创建工单必须设置接收人，也就是处理人
            notifyConfig.setHasReceiver(true);
            notifyConfig.setReceiverList(Collections.singletonList(receiveUser));
            // 设置抄送人
            notifyConfig.setHasCcList(false);
            if (!CollectionUtils.isEmpty(ccList)) {
                notifyConfig.setHasCcList(true);
                notifyConfig.setCcList(ccList);
            }

            // 设置通知事件
            notifyConfig.setEvent(param.getEvent());
            // 设置消息库的模板
            notifyConfig.setEmailTemplateId(param.getEmailTemplateId());
            notifyConfig.setEmailContent(param.getEmailContent());
            notifyConfig.setEmailSubject(param.getEmailSubject());
            notifyConfig.setSmsTemplateId(param.getSmsTemplateId());
            notifyConfig.setSmsContent(param.getSmsContent());
            notifyConfig.setSmsSubject(param.getSmsSubject());

            // 保存工单通知配置
            TicketNotifyConfig notifyConfigEntity = ticketNotifyConfigDao.saveTicketNotifyConfig(notifyConfig);
            result.add(notifyConfigEntity.getId());
        }
        return result;
    }


    /**
     * 手动创建工单 - 保存工单跟进人信息
     *
     * @param ticketParam 工单参数
     * @return TicketFlow 工单流转
     * @author jy.zhao
     * @date 2021/9/8 19:06
     **/
    private TicketFlow saveTicketFlow(InsertTicketParam ticketParam) {
        TicketFlow ticketFlow = new TicketFlow();
        ticketFlow.setOrgId(ticketParam.getOrgId());
        ticketFlow.setUserId(ticketParam.getUserId());
        ticketFlow.setTitle(ticketParam.getName());
        ticketFlow.setStatus(TicketFlowStatusEnum.ENABLED.getIndex());
        // 填充跟进人信息
        TicketFlow.FollowConfig followConfig = new TicketFlow.FollowConfig();
        // 在之前已经校验过followConfigParam不能为null
        InsertTicketParam.FollowConfig followConfigParam = ticketParam.getFollowConfig();
        followConfig.setFollowerId(followConfigParam.getUserId());
        followConfig.setFollowerName(followConfigParam.getName());
        followConfig.setFollowerEmail(followConfigParam.getEmail());
        followConfig.setFollowerFilter(followConfigParam.getUserFilter());
        followConfig.setRoleId(followConfigParam.getRoleId());
        followConfig.setRegion(followConfigParam.getRegionId());
        // 设置跟进人为空，转派给超级管理员
        followConfig.setEmptyFollowerHandle(SUBMIT_SUPER_ADMIN);
        ticketFlow.setFollowConfig(Collections.singletonList(followConfig));
        return ticketFlowDao.saveTicketFlow(ticketFlow);
    }
}
